Skip to content

Add ThreadContextStack injection capability #3810

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: 2.x
Choose a base branch
from

Conversation

yybmion
Copy link

@yybmion yybmion commented Jul 9, 2025

Implements custom ThreadContextStack injection capability as requested in #1507.

Users can now inject custom ThreadContextStack implementations just like ThreadContextMap.

Changes

  • ThreadContextStackFactory: New factory class following existing ThreadContextMapFactory pattern
  • Provider class: Extended with ThreadContextStack support while maintaining backward compatibility
  • ThreadContext: Added NOOP_STACK constant and updated initialization logic
  • System property support: log4j2.threadContextStack=com.example.MyCustomStack
  • Properties file support: Can be configured in log4j2.component.properties

Checklist

✅ Required checks

  • License: I confirm that my changes are submitted under the Apache License, Version 2.0.

  • Commit signatures: All commits are signed and verifiable. (See GitHub Docs on Commit Signature Verification).

  • Code formatting: The code is formatted according to the project’s style guide.

    How to check and fix formatting
    • To check formatting: ./mvnw spotless:check
    • To fix formatting: ./mvnw spotless:apply

    See the build instructions for details.

  • Build & Test: I verified that the project builds and all unit tests pass.

    How to build the project

    Run: ./mvnw verify

    See the build instructions for details.

🧪 Tests (select one)

  • I have added or updated tests to cover my changes.
  • No additional tests are needed for this change.

📝 Changelog (select one)

  • I added a changelog entry in src/changelog/.2.x.x. (See Changelog Entry File Guide).
  • This is a trivial change and does not require a changelog entry.

fixes #1507

- Add ThreadContextStackFactory following ThreadContextMapFactory pattern
- Extend Provider class with ThreadContextStack support (backward compatible)
- Add NOOP_STACK constant to ThreadContext
- Support log4j2.threadContextStack system property
- Add comprehensive tests
- Update package version for BND compliance

Fixes apache#1507
Copy link

github-actions bot commented Jul 9, 2025

Job Requested goals Build Tool Version Build Outcome Build Scan®
build-macos-latest clean install 3.9.8 Build Scan PUBLISHED
build-ubuntu-latest clean install 3.9.8 Build Scan PUBLISHED
build-windows-latest clean install 3.9.8 Build Scan PUBLISHED
Generated by gradle/develocity-actions

@vy
Copy link
Member

vy commented Jul 20, 2025

@yybmion, do you have a use case? Do you need this functionality for a certain system of yours that is deployed to production? Would you mind giving us some more context, please?

@vy vy self-assigned this Jul 20, 2025
@yybmion
Copy link
Author

yybmion commented Jul 20, 2025

Hi @vy,

Thank you for the question!

You previously provided positive feedback on this issue, stating:

"I think your assessment is correct: ThreadContext always creates a DefaultThreadContextStack instance for its ThreadContextStack. Ideally ThreadContextStack should be provided by a ThreadContextStackFactory just like ThreadContextMapFactory.createThreadContextMap() does."

I understand your concern about whether this is truly essential functionality. You're absolutely right that many use cases can be implemented using custom ThreadContextMap implementations — and I share some of that skepticism regarding strict necessity.

That said, I approached this change from two angles:

1. Architectural Consistency

As you previously noted, ThreadContextMap is already pluggable, but ThreadContextStack is still hardcoded. This PR completes the extensibility model, making both components consistent. The implementation also reuses existing SPI infrastructure already present in Provider.java (via getThreadContextStackInstance), so the cost of enabling this is minimal.

2. Purpose-Driven Use Cases

While Map and Stack may appear interchangeable on the surface, they serve distinct roles:

  • Map is useful for holding current-state metadata (e.g. userId=123).
  • Stack excels in tracking execution flow, nested context, and LIFO-based operations.

So while this feature may not be strictly required in the minimal sense, I think it adds clarity and purpose-driven extensibility that complements the existing Map-based model.

I believe this aligns with the design vision you described, and I'd be happy to discuss this further if you have additional concerns.

Best regards

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: To triage
Development

Successfully merging this pull request may close these issues.

Possibility to inject custom ThreadContextStack implementation
2 participants